package com.crazy.controller.sys;

import static com.crazy.common.page.Pager.DEFAULT_COUNT;
import static org.hibernate.criterion.Order.asc;
import static org.hibernate.criterion.Order.desc;
import static org.springframework.util.StringUtils.hasText;
import static org.springframework.validation.ValidationUtils.rejectIfEmptyOrWhitespace;

import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;

import org.springframework.data.domain.Page;
import org.springframework.security.web.bind.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import com.crazy.common.constants.Const;
import com.crazy.entity.sys.PubResource;
import com.crazy.entity.sys.PubUser;
import com.crazy.security.MyFilterInvocationSecurityMetadataSource;
import com.crazy.service.sys.PubResourceService;

/**
 * 资源控制器
 * 
 * @author Zhang Weiwei
 * @since 2013-9-19下午2:47:07
 */
@Controller
@RequestMapping("/sys/res")
public class PubResourceController {
	private static String VIEWNAME = "sys/res/";
	private static final String LISTURL = "sys/res/list";
	private static final String SUCCESS = "redirect:/success.jsp";
	@Inject
	private PubResourceService resService;
	@Inject
	private MyFilterInvocationSecurityMetadataSource source;

	/**
	 * 显示资源列表
	 * 
	 * @since 2013-9-21下午7:54:33
	 */
	@RequestMapping("/list")
	public String list(Integer pageNo, Model model, PubResource resource) {
		Page<PubResource> pager = this.resService.findPubResource(pageNo, DEFAULT_COUNT, resource, desc("createTime"));
		model.addAttribute("pager", pager);
		model.addAttribute("resource", resource);
		return VIEWNAME.concat("list");
	}

	/**
	 * 跳转到添加资源页面
	 * 
	 * @since 2013-9-21下午7:54:40
	 */
	@RequestMapping("/add")
	public String toAdd(Model model) {
		List<PubResource> list = this.resService.findAll(asc("priority"), asc("pubResource"));
		String jsonString = this.resService.listToJsonStringForAdd(list);
		PubResource resource = new PubResource();
		resource.setEnabled(Const.ENABLE.getStatus());
		model.addAttribute("jsonString", jsonString);
		model.addAttribute("resource", resource);
		return VIEWNAME.concat("add");
	}

	/**
	 * 添加资源
	 * 
	 * @since 2013-9-21下午7:54:45
	 */
	@RequestMapping("/doAdd")
	public String doAdd(@ModelAttribute("resource") PubResource resource, Errors errors, @AuthenticationPrincipal PubUser user, Model model) {
		if (this.validate(errors, resource)) {
			List<PubResource> list = this.resService.findAll(asc("priority"), asc("pubResource"));
			String jsonString = this.resService.listToJsonStringForAdd(list);
			model.addAttribute("jsonString", jsonString);
			model.addAttribute("resource", resource);
			return VIEWNAME.concat("add");
		}
		if (user != null) {
			resource.setCreator(user.getUserAccount());
		}
		resource.setCreateTime(new Date());
		if (!hasText(resource.getAuthorityName())) {
			resource.setAuthorityName(null);
		}
		this.resService.save(resource);
		this.updatePermission();
		model.addAttribute("url", LISTURL);
		return SUCCESS;
	}

	/**
	 * 跳转到修改资源页面
	 * 
	 * @since 2013-9-21下午7:54:50
	 */
	@RequestMapping("/update/{id}")
	public String toUpdate(@PathVariable String id, Model model) {
		PubResource resource = this.resService.get(id);
		List<PubResource> list = this.resService.findAll(asc("priority"), asc("pubResource"));
		String jsonString = this.resService.listToJsonStringForUpdate(list, resource);
		model.addAttribute("jsonString", jsonString);
		model.addAttribute("resource", resource);
		return VIEWNAME.concat("update");
	}

	/**
	 * 修改资源
	 * 
	 * @since 2013-9-21下午7:54:56
	 */
	@RequestMapping("/doUpdate")
	public String doUpdate(@ModelAttribute("resource") PubResource resource, Errors errors, Model model) {
		if (this.validate(errors, resource)) {
			List<PubResource> list = this.resService.findAll(asc("priority"), asc("pubResource"));
			String jsonString = this.resService.listToJsonStringForUpdate(list, resource);
			model.addAttribute("jsonString", jsonString);
			model.addAttribute("resource", resource);
			return VIEWNAME.concat("update");
		}
		PubResource entity = this.resService.get(resource.getResourceId());
		String authName = resource.getAuthorityName();
		authName = hasText(authName) ? authName : null;
		entity.setAuthorityName(authName);
		String url = resource.getResourceUrl();
		url = hasText(url) ? url : null;
		entity.setResourceUrl(url);
		entity.setPubResource(resource.getPubResource());
		entity.setEnabled(resource.getEnabled());
		entity.setPriority(resource.getPriority());
		entity.setResourceDesc(resource.getResourceDesc());
		entity.setResourceName(resource.getResourceName());
		entity.setResourceType(resource.getResourceType());
		entity.setTarget(resource.getTarget());
		this.resService.update(entity);
		this.updatePermission();
		model.addAttribute("url", LISTURL);
		return SUCCESS;
	}

	/**
	 * 删除资源
	 * 
	 * @since 2013-9-21下午7:55:01
	 */
	@RequestMapping("/delete/{id}")
	public String delete(@PathVariable String id, Model model) {
		this.resService.deleteByPK(id);
		this.updatePermission();
		model.addAttribute("url", LISTURL);
		return SUCCESS;
	}

	/**
	 * 验证资源对象
	 * 
	 * @since 2013-11-10下午4:13:32
	 */
	private boolean validate(Errors errors, PubResource resource) {
		if (hasText(resource.getResourceUrl())) {
			rejectIfEmptyOrWhitespace(errors, "authorityName", "authorityName.isNull");
		} else {
			resource.setResourceUrl(null);
		}
		rejectIfEmptyOrWhitespace(errors, "resourceName", "resourceName.isNull");
		rejectIfEmptyOrWhitespace(errors, "resourceType", "resourceType.isNull");
		rejectIfEmptyOrWhitespace(errors, "pubResource.resourceId", "pubResource.isNull");
		return errors.hasErrors();
	}

	@ModelAttribute("resType")
	public Map<String, String> resType() {
		Map<String, String> map = new LinkedHashMap<>();
		map.put(Const.MENU.getType(), Const.MENU.getName());
		map.put(Const.LINK.getType(), Const.LINK.getName());
		return map;
	}

	@ModelAttribute("resStatus")
	public Map<Integer, String> resStatus() {
		Map<Integer, String> map = new LinkedHashMap<>();
		map.put(Const.ENABLE.getStatus(), Const.ENABLE.getName());
		map.put(Const.DISABLED.getStatus(), Const.DISABLED.getName());
		return map;
	}

	/**
	 * 更新权限
	 */
	private void updatePermission() {
		synchronized (source) {
			this.source.loadResources();
		}
	}
}
